﻿using System.Collections.Generic;

using Microsoft.Xna.Framework;

using Ah.Testudin.Engine.Actors;

namespace Ah.Testudin.Engine.Graphics.Scenes
{
    public abstract class SceneNodeBase : ISceneNode
    {
        #region Protected Member Variables

        protected IList<ISceneNode> _childNodes;

        #endregion

        #region Properties

        public ISceneNode ParentNode { get; set; }

        #endregion

        #region Constructors

        public SceneNodeBase(
            string name,
            ActorId actorId,
            RenderPass renderPass,
            Matrix toWorldTransform)
        {
            this.ParentNode = null;

            _childNodes = new List<ISceneNode>();

            this.Properties = new SceneNodeProperties(
                name,
                actorId,
                toWorldTransform,
                Matrix.Invert(toWorldTransform),
                0,
                renderPass);
        }

        #endregion

        #region ISceneNode

        public SceneNodeProperties Properties { get; private set; }

        public virtual void Update(
            GameTime gameTime, 
            Scene scene)
        {
            foreach (ISceneNode currentChildNode in _childNodes)
            {
                currentChildNode.Update(
                    gameTime,
                    scene);
            }
        }

        public virtual void PreRender(Scene scene)
        {
            // Do nothing, used to push a new matrix on to the stack
        }

        public abstract void Render(Scene scene);

        public virtual void RenderChildren(Scene scene)
        {
            foreach (ISceneNode currentChild in _childNodes)
            {
                currentChild.PreRender(scene);

                if (currentChild.IsVisible(scene))
                {
                    currentChild.Render(scene);

                    currentChild.RenderChildren(scene);
                }

                currentChild.PostRender(scene);
            }
        }

        public virtual void PostRender(Scene scene)
        {
            // Do nothing for now, we used to pop the last matrix off the stack
        }

        public bool IsVisible(Scene scene)
        {
            return true;
        }

        public virtual void AddChildNode(ISceneNode childNode)
        {
            _childNodes.Add(childNode);

            childNode.ParentNode = this;

            Vector3 childPosition = childNode.Properties.ToWorldTransform.Translation;

            Vector3 childDirection = childPosition - this.Properties.ToWorldTransform.Translation;

            float newRadius = childDirection.Length() + childNode.Properties.Radius;

            if (newRadius > this.Properties.Radius)
            {
                this.Properties.Radius = newRadius;
            }
        }

        public virtual void RemoveChildNode(ISceneNode sceneNode)
        {
            _childNodes.Remove(sceneNode);
        }

        #endregion
    }
}
